package md.mru.frontend.controllers;

import md.mru.core.service.FolderService;
import org.primefaces.event.CaptureEvent;
import org.primefaces.model.CroppedImage;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

@ManagedBean
@SessionScoped
public class ImageAdministrationBean implements Serializable {

    private static final long serialVersionUID = 5290480510940810054L;

    @ManagedProperty(value = "#{folderService}")
    private FolderService folderService;

    private Long selectedFolderId;
    private StreamedContent folderImage;
    private CroppedImage croppedImage;
    private String imageName;

    private enum STEP {
        TAKE_PICTURE, CROP_PICTURE, SAVE_PICTURE
    }

    private STEP currentStep;

    public void loadFolderImage(long folderId) {
        this.selectedFolderId = folderId;
        byte[] image = folderService.loadFolderImage(folderId);
        if (image == null) {
            image = loadDefaultImage();
        }
        if (image != null) {
            ByteArrayInputStream stream = new ByteArrayInputStream(croppedImage.getBytes());
            folderImage = new DefaultStreamedContent(stream);
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            //folderImage = new DefaultStreamedContent(new ByteArrayInputStream(image));
        }
    }

    public byte[] loadDefaultImage() {
        Path path = Paths.get(FacesContext.getCurrentInstance().getExternalContext().getRealPath("//resources//profile//images") + File.separator + "default-avatar.png");
        try {
            return Files.readAllBytes(path);
        } catch (Exception e) {
            //addErrorMessage("profile_personal_load_image_error", null);
            return null;
        }
    }

    public void initWebCamDialog() {
        currentStep = STEP.TAKE_PICTURE;
    }

    public void onCapture(CaptureEvent event) {
        currentStep = STEP.CROP_PICTURE;
        this.writeImage(event.getData());
        folderImage = null;
        croppedImage = null;
    }

    public void crop() {
        currentStep = STEP.SAVE_PICTURE;
        //this.writeImage(croppedImage.getBytes());
        ByteArrayInputStream stream = new ByteArrayInputStream(croppedImage.getBytes());
        folderImage = new DefaultStreamedContent(stream);
        try {
            stream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void writeImage(byte[] image) {
        try {
            Path dir = Paths.get(FacesContext.getCurrentInstance().getExternalContext().getRealPath("//resources//profile//images"));
            final Path fileImage = Files.createTempFile(dir, "tmp-image", ".png");
            Files.write(fileImage, image, StandardOpenOption.WRITE);
            this.imageName = fileImage.getFileName().toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean renderControllers(STEP step) {
        return currentStep.equals(step);
    }

    /**
     * Uploads a folderImage and stores it temporary on specified path.
     *
     * @throws javax.faces.event.AbortProcessingException
     */
    /*public void handleFileUpload(FileUploadEvent event) throws AbortProcessingException {
        imageName = event.getFile().getFileName();
        File file = new File(getExternalContext().getRealPath("//resources//temp"));
        if (!file.exists()) {
            file.mkdir();
        }
        file = new File((getExternalContext().getRealPath("//resources//temp") + File.separator + imageName));
        byte[] bytes = event.getFile().getContents();
        imgSave(checkImageSize(bytes, 400, 300), file);

        croppedImage = null;
        cropImageRendered = true;
        processButtonsEnabled = true;
        imageRendered = false;
    }*/

    /*private byte[] checkImageSize(byte[] bytes, int w, int h) {
        BufferedImage image;
        byte[] bts = null;
        try {
            InputStream in = new ByteArrayInputStream(bytes);
            image = ImageIO.read(in);
            bts = resize(image, w, h);
        } catch (Exception e) {
            logger.error(Constants.ERROR_MESSAGE, e);
            addErrorMessage("profile_personal_load_image_error", null);
        }
        return bts;
    }*/
    private byte[] resize(BufferedImage image, int maxWidth, int maxHeight) throws IOException {

        int x = image.getWidth();
        int y = image.getHeight();
        int new_x;
        int new_y;

        if (x > maxWidth && x >= y) {
            new_x = maxWidth;
            new_y = (new_x * y / x);

        } else if (y > maxHeight && y > x) {
            new_y = maxHeight;
            new_x = (new_y * x / y);
        } else {
            new_x = x;
            new_y = y;
        }

        if (new_x != 0 && new_y != 0) {
            /*BufferedImage scaledImg = Scalr.resize(image, Scalr.Method.QUALITY, new_x, new_y, Scalr.OP_ANTIALIAS);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(scaledImg, "jpg", baos);
            bytes = baos.toByteArray();*/
        }
        return new byte[0];
    }

    /**
     * Gets StreamedContent object from bytes
     *
     * @param bytes byte[]   folderImage content in bytes
     * @return StreamedContent, streamed folderImage
     */
    /*private StreamedContent getImageFromBytes(byte[] bytes) {
        StreamedContent content = new DefaultStreamedContent(new ByteArrayInputStream(bytes));


        return content;
    }*/


    /**
     * Resize the uploaded folderImage and stores it to database
     */
    /*public void resizeImage() {
        File file = new File(getExternalContext().getRealPath("//resources//temp") + File.separator + imageName);
        BufferedImage image;

        if (userImage == null) {
            userImage = new UserImageDto();
        }
        try {
            image = ImageIO.read(file);
            bytes = resize(image, Constants.IMAGE_WIDTH, Constants.IMAGE_HEIGHT);
            newImage = getImageFromBytes(bytes);

        } catch (IOException e) {
            logger.error(Constants.ERROR_MESSAGE, e);
            addErrorMessage("profile_personal_load_image_error", e);
        }
        imageRendered = true;
        processButtonsEnabled = false;
        saveImage();
    }*/

    /**
     * Stores folderImage on specified path
     *
     * @param bytes byte[]
     * @param file  File
     */
    /*public void imgSave(byte[] bytes, File file) {
        try {
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(bytes);
            fos.flush();
            fos.close();
        } catch (Exception e) {
            logger.error(Constants.ERROR_MESSAGE, e);
            addErrorMessage("profile_personal_save_image_error", null);
        }
    }*/

    /**
     * Saves folderImage in database.
     */
    /*public void saveImage(){
        saveImage(bytes);
        saveBtnActive = false;
    }
*/

    /**
     * Stores or updates folderImage in database for currently user
     */
    /*public void saveImage() {
        if (userImage == null) {
            userImage = new UserImageDto();
        }
        userImage.setImageName(imageName);
        userImage.setImage(bytes);
        try {
            if (userImage.getImageId() != null) {
                simulatorService.updateImage(userImage);
                addInfoMessage("profile_personal_image_updated", null);

            } else {
                userImage.setUser(getCurrentUser());
                userImage.setImageId(simulatorService.createImage(userImage));
                addInfoMessage("profile_personal_image_saved", null);
            }
        } catch (Exception e) {
            logger.error(Constants.ERROR_MESSAGE, e);
            addErrorMessage("profile_personal_save_image_error", null);
        }
    }*/

    /**
     * Deletes all images from temporary directory
     * Removes folderImage bean from session
     */
    /*public void handleClose() {
        processButtonsEnabled = false;
        File file = new File(getExternalContext().getRealPath("//resources//temp"));
        delete(file);

        HttpSession session = (HttpSession) getExternalContext().getSession(false);
        session.removeAttribute("imageBean");
    }*/

    /**
     * Deletes all files from specified directory
     *
     * @return boolean if file successfully deleted.
     */
    /*public boolean delete(File file) {
        if (file.isDirectory())
            if (file.list().length != Constants.ZERO) {
                String files[] = file.list();
                for (String temp : files) {
                    try {
                        File fileDelete = new File(file, temp);
                        return fileDelete.delete();
                    } catch (Exception e) {
                        logger.error(Constants.ERROR_MESSAGE, e);
                    }
                }
            }
        return false;
    }*/
    public StreamedContent getFolderImage() {
        return folderImage;
    }

    public CroppedImage getCroppedImage() {
        return croppedImage;
    }

    public void setCroppedImage(CroppedImage croppedImage) {
        this.croppedImage = croppedImage;
    }

    public void setFolderService(FolderService folderService) {
        this.folderService = folderService;
    }

    public String getImageName() {
        return imageName;
    }
}
